﻿#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QStandardItemModel>
#include <QStorageInfo>
#include <QTextStream>

MainWindow::MainWindow(QWidget* parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    this->setWindowTitle(QString::fromUtf8("新动态IO加速软件"));

    m_pShellProcess = new QProcess(this);
    m_pShellProcessGetStatus = new QProcess(this);

    treeViewCacheTask_init();

    connect(this, SIGNAL(createCacheTaskDigShow_signal()),
        &m_createCacheTaskDig, SLOT(createCacheTaskDigShow_slot()));
    connect(this, SIGNAL(shellProcessCmdReadOutput_signal(QString&, QObject*)),
        &m_createCacheTaskDig, SLOT(shellProcessCmdReadOutput_slot(QString&, QObject*)));

    connect(&m_createCacheTaskDig, SIGNAL(shellProcessCmdWrite_signal(QString&, QObject*)),
        this, SLOT(shellProcessCmdWrite_slot(QString&, QObject*)));
    connect(&m_cacheTaskParamsSetDig, SIGNAL(shellProcessCmdWrite_signal(QString&, QObject*)),
        this, SLOT(shellProcessCmdWrite_slot(QString&, QObject*)));

    connect(&m_cacheTaskParamsSetDig, SIGNAL(cacheTaskStartOk_signal(CacheTaskInfo*)),
        this, SLOT(cacheTaskStartOk_slot(CacheTaskInfo*)));

    connect(&m_createCacheTaskDig, SIGNAL(cacheTaskParamsSetDigShow_signal(QList<Block_Info>*, QList<Block_Info>*)),
        &m_cacheTaskParamsSetDig, SLOT(cacheTaskParamsSetDigShow_slot(QList<Block_Info>*, QList<Block_Info>*)));

    connect(m_pShellProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(on_readoutput()));
    connect(m_pShellProcess, SIGNAL(readyReadStandardError()), this, SLOT(on_readerror()));

    connect(m_pShellProcessGetStatus, SIGNAL(readyReadStandardOutput()), this, SLOT(on_readoutput_status_get()));

    connect(ui->treeView_cacheTask, SIGNAL(pressed(const QModelIndex&)), this, SLOT(treeItemPressed(const QModelIndex&)));

    m_statusRefreshTimer.setInterval(5000);
    connect(&m_statusRefreshTimer, SIGNAL(timeout()), this, SLOT(statusRefreshTimer_slot()));

    m_pShellProcess->start("bash");
    m_pShellProcess->waitForStarted();
    /*m_pShellCmdFrom = this;
    m_pShellProcess->write("sudo -S lsblk -J" "\n");*/

    m_pShellProcessGetStatus->start("bash");
    m_pShellProcessGetStatus->waitForStarted();

    SystemParams::system_init();

#if 0
    cacheTasks_init();
    m_pCacheTaskInfoSelected = nullptr;

    pushButtonsStatus_init();
#endif
}

// 析构函数
MainWindow::~MainWindow()
{
    if (m_pShellProcess) {
        m_pShellProcess->terminate();
        m_pShellProcess->waitForFinished();
        delete m_pShellProcess;
    }

    if (m_pShellProcessGetStatus) {
        m_pShellProcessGetStatus->terminate();
        m_pShellProcessGetStatus->waitForFinished();
        delete m_pShellProcessGetStatus;
    }

    delete ui;
}

void MainWindow::pushButtonsStatus_init()
{
    ui->pushButton_deleteTask->setEnabled(false);
    ui->pushButton_suspendTask->setEnabled(false);
    ui->pushButton_continueTask->setEnabled(false);
}

void MainWindow::on_readoutput()
{
    /*插槽on_readoutput()连接到readyReadStandardOutput()的信号,
     在构造函数中创建m_pShellProcess的实例*/
    QString content = m_pShellProcess->readAllStandardOutput().data();
    qDebug("%s content=%s", __func__, content.toLatin1().data());

    if (m_pShellCmdFrom != this) {
        emit shellProcessCmdReadOutput_signal(content, m_pShellCmdFrom);
    } else {
        qDebug("%s local processing", __func__);
    }
}

void MainWindow::on_readoutput_status_get()
{
    QString content = m_pShellProcessGetStatus->readAllStandardOutput().data();
    qDebug("%s content=%s", __func__, content.toLatin1().data());

    cacheTaskStatusContent_parse(content);
}
/*解析一个QString类型的参数content。该字符串是由一些有特定格式的缓存状态信息组成的，
 *函数的目标是从该字符串中提取并计算缓存的读/写命中次数以及命中率，并更新到一个表格中。*/
void MainWindow::cacheTaskStatusContent_parse(QString& content)
{
    QStringList str_list = content.split("\n");
    CacheStatusInfo status_info;
    status_info.reads_num = 0;
    status_info.writes_num = 0;
    status_info.reads_hit_num = 0;
    status_info.writes_hit_num = 0;
    status_info.reads_hit_percent = 0;
    status_info.writes_hit_percent = 0;

    /*函数通过检查str_row中是否包含特定的字符串，以及是否同时包含uncached和disk字符串，
     * 来确定该行是否包含有用的缓存信息。如果该行包含有用的信息，则根据该行字符串的格式，
     * 提取其中的读/写命中次数，然后计算命中率并更新status_info结构体。*/
    for (int32 i = 0; i < str_list.count(); i++) {
        QString str_row = str_list.at(i);
        int32 position_rest_start = 0;

        if (str_row.contains("reads(") && !str_row.contains("uncached") && !str_row.contains("disk")) {
            int32 position_start = str_row.indexOf("reads(");
            int32 position_end = str_row.indexOf(")");
            if (position_end > position_start) {
                position_rest_start = position_end + 1;
                int32 size = sizeof("reads(");
                int32 len = position_end - (position_start + size) + 1;
                QString reads_str = str_row.mid(position_start + size - 1, len);
                qDebug("%s reads_str=%s", __func__, reads_str.toLocal8Bit().data());
                status_info.reads_num = reads_str.toInt();

                str_row = str_row.mid(position_rest_start, str_row.length() - position_rest_start);
            }
        }

        if (str_row.contains("writes(") && !str_row.contains("uncached") && !str_row.contains("disk")) {
            int32 position_start = str_row.indexOf("writes(");
            int32 position_end = str_row.indexOf(")");
            if (position_end > position_start) {
                position_rest_start = position_end + 1;
                int32 size = sizeof("writes(");
                int32 len = position_end - (position_start + size) + 1;
                QString writes_str = str_row.mid(position_start + size - 1, len);
                qDebug("%s writes_str=%s", __func__, writes_str.toLocal8Bit().data());
                status_info.writes_num = writes_str.toInt();

                str_row = str_row.mid(position_rest_start, str_row.length() - position_rest_start);
            }
        }

        if (str_row.contains("read hits(")) {
            int32 position_start = str_row.indexOf("read hits(");
            int32 position_end = str_row.indexOf(")");
            if (position_end > position_start) {
                position_rest_start = position_end + 1;
                int32 size = sizeof("read hits(");
                int32 len = position_end - (position_start + size) + 1;
                QString reads_hit_str = str_row.mid(position_start + size - 1, len);
                qDebug("%s reads_hit_str=%s", __func__, reads_hit_str.toLocal8Bit().data());
                status_info.reads_hit_num = reads_hit_str.toInt();

                str_row = str_row.mid(position_rest_start, str_row.length() - position_rest_start);
            }
        }

        else if (str_row.contains("write hits(")) {
            int32 position_start = str_row.indexOf("write hits(");
            int32 position_end = str_row.indexOf(")");
            if (position_end > position_start) {
                position_rest_start = position_end + 1;
                int32 size = sizeof("write hits(");
                int32 len = position_end - (position_start + size) + 1;
                QString writes_hit_str = str_row.mid(position_start + size - 1, len);
                qDebug("%s writes_hit_str=%s", __func__, writes_hit_str.toLocal8Bit().data());
                status_info.writes_hit_num = writes_hit_str.toInt();
            }
        }
    }

    if (status_info.reads_num != 0) {
        status_info.reads_hit_percent = status_info.reads_hit_num * 100 / status_info.reads_num;
    }

    if (status_info.writes_num != 0) {
        status_info.writes_hit_percent = status_info.writes_hit_num * 100 / status_info.writes_num;
    }

    // 将status_info结构体中的数据更新到一个表格中。
    tableWidgetDynamicStatus_update(&status_info);
}

void MainWindow::tableWidgetDynamicStatus_update(CacheStatusInfo* pInfo)
{
    // 显示读取请求的总数
    ui->tableWidget_dynamicStatus->setItem(0, 1,
        new QTableWidgetItem(readsWritesSizeToStr_convert(pInfo->reads_num)));
    // 显示导致缓存命中的读取请求数
    ui->tableWidget_dynamicStatus->setItem(1, 1,
        new QTableWidgetItem(readsWritesSizeToStr_convert(pInfo->reads_hit_num)));
    // 显示导致缓存命中的读取请求的百分比
    ui->tableWidget_dynamicStatus->setItem(2, 1,
        new QTableWidgetItem(QString::number(pInfo->reads_hit_percent)));
    // 显示写入请求的总数
    ui->tableWidget_dynamicStatus->setItem(3, 1,
        new QTableWidgetItem(readsWritesSizeToStr_convert(pInfo->writes_num)));
    // 显示导致缓存命中的写入请求数
    ui->tableWidget_dynamicStatus->setItem(4, 1,
        new QTableWidgetItem(readsWritesSizeToStr_convert(pInfo->writes_hit_num)));
    // 显示导致缓存命中的写入请求的百分比
    ui->tableWidget_dynamicStatus->setItem(5, 1,
        new QTableWidgetItem(QString::number(pInfo->writes_hit_percent)));
}

QString MainWindow::readsWritesSizeToStr_convert(int32 size)
{
    int32 size_int = size * m_pCacheTaskInfoSelected->m_granularitySize;
    QString size_str;

    if (size_int < 1024) {
        size_str = QString("%1 KB").arg(QString::number(size_int));
    } else if (size_int < 1024 * 1024) {
        size_str = QString("%1 MB").arg(QString::number(size_int / 1024));
    } else {
        size_str = QString("%1 GB").arg(QString::number(size_int / (1024 * 1024)));
    }

    return size_str;
}

void MainWindow::on_readerror()
{
    // qWarning("%s:%s", __func__, m_pShellProcess->readAllStandardError().data());
}

// 在树形视图中选中一个任务时，更新任务相关的界面元素，包括任务状态、按钮状态、静态状态表格等
void MainWindow::treeItemPressed(const QModelIndex& index)
{
    // 首先获取被选中项的行数 row，用于后面从模型中获取对应的数据
    int32 row = index.row();
    qDebug("%s enter, row=%d", __func__, row);

    // 获取被选中项的父项parent_index，并判断其行数是否为-1，如果不为-1，说明该项不是根节点，直接返回，不做任何操作
    QModelIndex parent_index = index.parent();
    qDebug("%s parent_index.row()=%d", __func__, parent_index.row());

    if (parent_index.row() != -1) {
        return;
    }

    /*如果被选中项是根节点，就从模型中获取对应的数据，根据获取到的 uuid 填充静态状态表格，
     * 将选中的任务信息保存在变量 m_pCacheTaskInfoSelected 中，
     * 并调用 flashCacheFile_modify 函数更新缓存文件列表。*/
    QStandardItem* item = m_pTreeViewModel->item(row, 0);
    QString uuid = item->data().toString();
    qDebug("%s uuid=%s", __func__, uuid.toLocal8Bit().data());

    tableWidgetStaticStatus_fill(uuid);

    m_treeViewRowSelected = row;
    m_pCacheTaskInfoSelected = &m_cacheTaskMap[uuid];
    flashCacheFile_modify(m_pCacheTaskInfoSelected);

    // 根据任务状态设置相应的按钮状态，如果任务处于停止状态，暂停按钮设为不可用，继续按钮设为可用，反之亦然。
    ui->pushButton_deleteTask->setEnabled(true);

    if (m_pCacheTaskInfoSelected->m_taskStatus == CACHE_TASK_STOP) {
        ui->pushButton_suspendTask->setEnabled(false);
        ui->pushButton_continueTask->setEnabled(true);
    } else {
        ui->pushButton_suspendTask->setEnabled(true);
        ui->pushButton_continueTask->setEnabled(false);
    }

    // 将任务状态设置为标签的文本，并启动状态刷新定时器。
    ui->label_taskStatus->setText(
        SystemParams::cacheTaskStatusToStr_convert(m_pCacheTaskInfoSelected->m_taskStatus));

    m_statusRefreshTimer.start();
}

// 当m_statusRefreshTimer定时器的时间到达后，就会调用该槽函数。
void MainWindow::statusRefreshTimer_slot()
{
    qDebug("%s enter!", __func__);

    /*使用sudo权限执行CMD_FLASH_CACHE_STATUS命令，并将SystemParams::instance_get()
     * ->m_userPasswd作为参数传递给该命令，以获取闪存缓存的状态信息。*/
    QString cmd = QString("echo \"%1\"|sudo -S %2").arg(SystemParams::instance_get()->m_userPasswd).arg(QString(CMD_FLASH_CACHE_STATUS));
    shellProcessCmdGetStatus_write(cmd);
}

void MainWindow::cacheTaskStartOk_slot(CacheTaskInfo* pInfo)
{
    qDebug("%s enter!", __func__);

    // 将该任务的状态设置为CACHE_TASK_RUNNING，然后创建该任务的缓存，并更新任务列表视图
    pInfo->m_taskStatus = CACHE_TASK_RUNNING;

    cacheTask_create(pInfo);

    treeViewCacheTask_add(pInfo);
    treeViewCacheTask_update();

    // 将该任务的信息保存到本地文件中
    cacheTaskInfo_save(pInfo);

    // 将该任务添加到缓存任务字典m_cacheTaskMap中
    m_cacheTaskMap[pInfo->m_taskUuid] = *pInfo;

    /*设置当前任务状态标签的文本为CACHE_TASK_RUNNING，并将该任务所使用的缓存ID
     * 在系统参数中的缓存ID占用数组cacheIdUsedArray中标记为已使用。*/
    ui->label_taskStatus->setText(
        SystemParams::cacheTaskStatusToStr_convert(CACHE_TASK_RUNNING));

    SystemParams::cacheIdUsedArray_set(pInfo->m_taskIndex, true);
}

void MainWindow::mainWindowShow_slot()
{
    cacheTasks_init();
    m_pCacheTaskInfoSelected = nullptr;

    pushButtonsStatus_init();

    show();
}

// 根据给定的CacheTaskInfo对象创建并启动缓存任务pInfo。
void MainWindow::cacheTask_create(CacheTaskInfo* pInfo)
{
    if (pInfo->m_cacheType == L1_CACHE) {
        // first step create ram disk
        QString create_ram_disk = QString("echo \"%1\"|sudo -S %2%3 max_part=0").arg(SystemParams::instance_get()->m_userPasswd).arg(CMD_CREATE_RAM_DISK).arg(QString::number(pInfo->m_cacheSize * 1024));
        shellProcessCmdWrite_slot(create_ram_disk, this);
    }

    if (pInfo->m_taskStatus == CACHE_TASK_RUNNING) {
        // second step modify /etc/init.d/flashcache 在缓存设备和后备存储设备之间建立缓存映射
        flashCacheFile_modify(pInfo);

        /*third step mount
         * 使用mount带有适当参数的命令将缓存设备挂载到指定的挂载点。*/
        QString mount_cmd = QString("echo \"%1\"|sudo -S mount %2 %3").arg(SystemParams::instance_get()->m_userPasswd).arg(pInfo->m_blockInfo.m_name).arg(pInfo->m_blockInfo.m_mountedPoint);
        shellProcessCmdWrite_slot(mount_cmd, this);

        // fourth step start flashcache
        QString start_flashcache = QString("echo \"%1\"|sudo -S %2").arg(SystemParams::instance_get()->m_userPasswd).arg(QString(CMD_FLASH_CACHE_START));
        shellProcessCmdWrite_slot(start_flashcache, this);
        // shellProcessCmdWrite_slot方法用于将这些命令中的每一个作为shell进程执行，指针this作为回调槽传递以接收shell进程的输出。
    }
}

void MainWindow::cacheTask_delete(QString& uuid)
{
    QString delete_flashcache = QString("echo \"%1\"|sudo -S %2 %3").arg(SystemParams::instance_get()->m_userPasswd).arg(CMD_FLASH_CACHE_DELETE).arg(uuid);
    shellProcessCmdWrite_slot(delete_flashcache, this);
}

void MainWindow::treeViewCacheTask_add(CacheTaskInfo* pInfo)
{
    // 一级节点，加入mModel
    QList<QStandardItem*> items_taskInfo;
    QString task_nameInfo = QString("%1(%2)").arg(pInfo->m_taskName).arg(pInfo->m_taskUuid);
    QStandardItem* item_taskNameInfo = new QStandardItem(task_nameInfo);
    item_taskNameInfo->setData(pInfo->m_taskUuid);
    items_taskInfo.append(item_taskNameInfo);
    m_pTreeViewModel->appendRow(items_taskInfo);

    // 二级节点,加入第1个一级节点
    QList<QStandardItem*> items_blockInfo;
    QStandardItem* item_blockName = new QStandardItem(pInfo->m_blockInfo.m_name);
    QStandardItem* item_blockType = new QStandardItem(SystemParams::blockTypeToString_convert(pInfo->m_blockInfo.m_type));
    QStandardItem* item_blockSize = new QStandardItem(pInfo->m_blockInfo.m_size);
    QStandardItem* item_mountedPoint = new QStandardItem(pInfo->m_blockInfo.m_mountedPoint);

    items_blockInfo.append(item_blockName);
    items_blockInfo.append(item_blockType);
    items_blockInfo.append(item_blockSize);
    items_blockInfo.append(item_mountedPoint);
    item_taskNameInfo->appendRow(items_blockInfo);
}

void MainWindow::cacheTaskInfo_save(CacheTaskInfo* pInfo)
{
    QString path = SystemParams::instance_get()->m_cacheTaskPath
        + QString("/") + pInfo->m_taskName + QString(".json");

    qDebug("%s path=%s", __func__, path.toUtf8().data());
    SystemParams::cacheTaskInfoFile_save(path, pInfo);
}

// 更新显示缓存任务信息的树形结构视图
void MainWindow::treeViewCacheTask_update()
{
    // 缓存任务信息树形结构视图的数据模型
    m_pTreeViewModel->setHorizontalHeaderLabels(QStringList() << QString::fromUtf8("名称")
                                                              << QString::fromUtf8("类型") << QString::fromUtf8("容量")
                                                              << QString::fromUtf8("挂载点"));

    ui->treeView_cacheTask->setColumnWidth(0, 380); // 列宽
    ui->treeView_cacheTask->setColumnWidth(1, 100);
    ui->treeView_cacheTask->setColumnWidth(2, 100);
    ui->treeView_cacheTask->setColumnWidth(3, 100);
    ui->treeView_cacheTask->expandAll(); // 展开所有树形节点
}

void MainWindow::treeViewCacheTask_init()
{
    m_pTreeViewModel = new QStandardItemModel(ui->treeView_cacheTask);
    ui->treeView_cacheTask->setModel(m_pTreeViewModel);
}

// 读取缓存任务目录下的所有缓存任务文件，并将这些缓存任务加入到缓存任务树形视图中
void MainWindow::cacheTasks_init()
{
    QDir dir(SystemParams::instance_get()->m_cacheTaskPath);

    QStringList nameFilters;
    // 设置文件过滤格式
    nameFilters << "*.json";
    // 将过滤后的文件名称存入到files列表中
    QStringList files = dir.entryList(nameFilters, QDir::Files | QDir::Readable, QDir::Name);

    for (uint16 i = 0; i < files.size(); i++) {
        QString file_name = files.at(i);
        qDebug("%s file_name=%s", __func__, file_name.toUtf8().data());
        QString path = SystemParams::instance_get()->m_cacheTaskPath
            + QString("/") + file_name;
        qDebug("%s path=%s", __func__, path.toUtf8().data());
        CacheTaskInfo info;
        if (SystemParams::cacheTaskInfoFile_get(path, &info) == 0) {
            qDebug("%s info.m_taskName=%s", __func__, info.m_taskName.toUtf8().data());

            cacheTask_create(&info);
            treeViewCacheTask_add(&info);
            treeViewCacheTask_update();

            m_cacheTaskMap[info.m_taskUuid] = info;
            SystemParams::cacheIdUsedArray_set(info.m_taskIndex, true);
        }
    }

    // QString uuid_test = SystemParams::cacheTaskUuid_generate();
    // qDebug("sizeof(int)=%d", sizeof(int));
    // qDebug("uuid_test = %s", uuid_test.toLocal8Bit().data());
}

void MainWindow::on_pushButton_addTask_clicked()
{
    emit createCacheTaskDigShow_signal();
}

void MainWindow::shellProcessCmdWrite_slot(QString& cmd, QObject* from)
{
    qDebug("%s cmd=%s", __func__, cmd.toLocal8Bit().data());

    m_pShellCmdFrom = from;
    m_pShellProcess->write(cmd.toLocal8Bit() + "\n");
}

void MainWindow::shellProcessCmdGetStatus_write(QString& cmd)
{
    qDebug("%s cmd=%s", __func__, cmd.toLocal8Bit().data());
    m_pShellProcessGetStatus->write(cmd.toLocal8Bit() + "\n");
}

// 对 flashcache 脚本文件的修改，以生成缓存任务需要的配置信息
void MainWindow::flashCacheFile_modify(CacheTaskInfo* pInfo)
{
    // 读取 flashcache 脚本文件的全部内容，保存到字符串str_all中
    QString str_all;
    QStringList str_list;
    QFile read_file("/etc/init.d/flashcache");

    if (read_file.open((QIODevice::ReadOnly | QIODevice::Text))) {
        QTextStream stream(&read_file);
        str_all = stream.readAll();
    }
    read_file.close();

    QFile write_file("/etc/init.d/flashcache");
    // write_file.setPermissions(QFile::WriteOwner);
    if (write_file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        // 字符串分割函数split()，将读取的内容按行分割，生成一个字符串列表str_list
        qDebug("%s flashcache open is ok", __func__);
        QTextStream stream(&write_file);
        QStringList str_list = str_all.split("\n");

        for (int32 i = 0; i < str_list.count(); i++) {
            if (i == str_list.count() - 1) {
                // 最后一行不需要换行
                stream << str_list.at(i);
            } else {
                stream << str_list.at(i) << '\n';
            }

            // 如果包含SSD_DISK，即SSD磁盘设备名列表的定义行，则在下一行写入缓存设备名。
            if (str_list.at(i).contains("SSD_DISK=(")) {
                QString tempStr = str_list.at(i + 1);
                tempStr.replace(0, tempStr.length(), pInfo->m_cacheName);
                stream << tempStr << '\n';
                i += 1;
            } else if (str_list.at(i).contains("BLOCK_SIZE=(")) // 缓存块大小
            {
                QString tempStr = str_list.at(i + 1);
                tempStr.replace(0, tempStr.length(),
                    QString::number(pInfo->m_granularitySize) + QString("k"));
                stream << tempStr << '\n';
                i += 1;
            } else if (str_list.at(i).contains("CACHE_MODE=(")) // 缓存模式
            {
                QString cache_mode = "thru";
                if (pInfo->m_cacheStrategyType == CACHE_READ) {
                    cache_mode = "thru";
                } else if (pInfo->m_cacheStrategyType == CACHE_READ_WRITE) {
                    cache_mode = "back";
                }

                QString tempStr = str_list.at(i + 1);
                tempStr.replace(0, tempStr.length(), cache_mode);
                stream << tempStr << '\n';
                i += 1;
            } else if (str_list.at(i).contains("BACKEND_DISK=(")) // 后端磁盘设备名
            {
                QString tempStr = str_list.at(i + 1);
                tempStr.replace(0, tempStr.length(), pInfo->m_blockInfo.m_name);
                stream << tempStr << '\n';
                i += 1;
            } else if (str_list.at(i).contains("CACHEDEV_NAME=(")) // 缓存设备名
            {
                QString tempStr = str_list.at(i + 1);
                QString cache_dev_str = QString("cachedev%1").arg(QString::number(pInfo->m_taskIndex));
                tempStr.replace(0, tempStr.length(), cache_dev_str);
                stream << tempStr << '\n';
                i += 1;
            } else if (str_list.at(i).contains("MOUNTPOINT=(")) // 后端磁盘挂载点
            {
                QString tempStr = str_list.at(i + 1);
                tempStr.replace(0, tempStr.length(), pInfo->m_blockInfo.m_mountedPoint);
                stream << tempStr << '\n';
                i += 1;
            } else if (str_list.at(i).contains("UUID_STR=(")) // 缓存任务 UUID
            {
                QString tempStr = str_list.at(i + 1);
                tempStr.replace(0, tempStr.length(), pInfo->m_taskUuid);
                stream << tempStr << '\n';
                i += 1;
            }
        }
    }

    write_file.close();
}

void MainWindow::tableWidgetStaticStatus_fill(QString uuid)
{
    CacheTaskInfo info = m_cacheTaskMap[uuid];

    if (info.m_cacheType == L1_CACHE) {
        QString cache_size = QString("%1MB").arg(info.m_cacheSize);

        ui->tableWidget_staticStatus->setItem(0, 1, new QTableWidgetItem(cache_size));
        ui->tableWidget_staticStatus->setItem(1, 1, new QTableWidgetItem(QString::fromUtf8("读写共享")));
        ui->tableWidget_staticStatus->setItem(2, 1, new QTableWidgetItem(QString::fromUtf8("禁用")));
        ui->tableWidget_staticStatus->setItem(3, 1, new QTableWidgetItem("-"));
        ui->tableWidget_staticStatus->setItem(4, 1, new QTableWidgetItem("-"));
    } else {
        ui->tableWidget_staticStatus->setItem(0, 1, new QTableWidgetItem(QString::fromUtf8("禁用")));
        ui->tableWidget_staticStatus->setItem(1, 1, new QTableWidgetItem(QString::fromUtf8("-")));
        ui->tableWidget_staticStatus->setItem(2, 1, new QTableWidgetItem(info.m_diskCacheSize));
        ui->tableWidget_staticStatus->setItem(3, 1, new QTableWidgetItem(QString::fromUtf8("读写共享")));
        ui->tableWidget_staticStatus->setItem(4, 1, new QTableWidgetItem("-"));
    }

    QString granularity_size = QString("%1KB").arg(info.m_granularitySize);
    ui->tableWidget_staticStatus->setItem(5, 1, new QTableWidgetItem(granularity_size));

    QString strategy;
    if (info.m_cacheStrategyType == CACHE_READ) {
        strategy = QString::fromUtf8(CACHE_READ_STR);
    } else {
        strategy = QString::fromUtf8(CACHE_READ_WRITE_STR);
    }
    ui->tableWidget_staticStatus->setItem(6, 1, new QTableWidgetItem(strategy));

    ui->tableWidget_staticStatus->setItem(7, 1, new QTableWidgetItem(QString::fromUtf8("禁用")));
    ui->tableWidget_staticStatus->setItem(8, 1, new QTableWidgetItem("-"));
    ui->tableWidget_staticStatus->setItem(9, 1, new QTableWidgetItem("-"));
    ui->tableWidget_staticStatus->setItem(10, 1, new QTableWidgetItem(QString::fromUtf8("启用")));
}

void MainWindow::on_pushButton_deleteTask_clicked()
{
    if (m_pCacheTaskInfoSelected == nullptr) {
        return;
    }

    treeViewRow_delete(m_treeViewRowSelected);

    QString file_path = SystemParams::instance_get()->m_cacheTaskPath
        + QString("/") + m_pCacheTaskInfoSelected->m_taskName + QString(".json");
    cacheTaskInfoFile_delete(file_path);

    QString delete_ram = QString("echo \"%1\"|sudo -S %2").arg(SystemParams::instance_get()->m_userPasswd).arg(QString(CMD_DELETE_RAM));
    shellProcessCmdWrite_slot(delete_ram, this);

    QString delete_flashcache = QString("echo \"%1\"|sudo -S %2").arg(SystemParams::instance_get()->m_userPasswd).arg(QString(CMD_FLASH_CACHE_DELETE));
    shellProcessCmdWrite_slot(delete_flashcache, this);

    treeViewCacheTask_update();
    m_cacheTaskMap.remove(m_pCacheTaskInfoSelected->m_taskUuid);
    SystemParams::cacheIdUsedArray_set(m_pCacheTaskInfoSelected->m_taskIndex, false);
    m_pCacheTaskInfoSelected = nullptr;
    ui->pushButton_deleteTask->setEnabled(false);
    m_statusRefreshTimer.stop();

    pushButtonsStatus_init();
}

void MainWindow::treeViewRow_delete(int32 row)
{
    if (row < 0) {
        return;
    }

    m_pTreeViewModel->removeRow(row);
}

void MainWindow::cacheTaskInfoFile_delete(QString& path)
{
    QFile::remove(path);
}

void MainWindow::on_pushButton_suspendTask_clicked()
{
    if (m_pCacheTaskInfoSelected == nullptr) {
        return;
    }

    QString suspend_flashcache = QString("echo \"%1\"|sudo -S %2").arg(SystemParams::instance_get()->m_userPasswd).arg(QString(CMD_FLASH_CACHE_SUSPEND));
    shellProcessCmdWrite_slot(suspend_flashcache, this);

    m_pCacheTaskInfoSelected->m_taskStatus = CACHE_TASK_STOP;
    cacheTaskInfo_save(m_pCacheTaskInfoSelected);

    ui->label_taskStatus->setText(
        SystemParams::cacheTaskStatusToStr_convert(CACHE_TASK_STOP));

    ui->pushButton_suspendTask->setEnabled(false);
    ui->pushButton_continueTask->setEnabled(true);
}

void MainWindow::on_pushButton_continueTask_clicked()
{
    if (m_pCacheTaskInfoSelected == nullptr) {
        return;
    }

    // mount
    QString mount_cmd = QString("echo \"%1\"|sudo -S mount %2 %3").arg(SystemParams::instance_get()->m_userPasswd).arg(m_pCacheTaskInfoSelected->m_blockInfo.m_name).arg(m_pCacheTaskInfoSelected->m_blockInfo.m_mountedPoint);
    shellProcessCmdWrite_slot(mount_cmd, this);

    QString continue_flashcache = QString("echo \"%1\"|sudo -S %2").arg(SystemParams::instance_get()->m_userPasswd).arg(QString(CMD_FLASH_CACHE_CONTINUE));
    shellProcessCmdWrite_slot(continue_flashcache, this);

    m_pCacheTaskInfoSelected->m_taskStatus = CACHE_TASK_RUNNING;
    cacheTaskInfo_save(m_pCacheTaskInfoSelected);

    ui->label_taskStatus->setText(
        SystemParams::cacheTaskStatusToStr_convert(CACHE_TASK_RUNNING));

    ui->pushButton_suspendTask->setEnabled(true);
    ui->pushButton_continueTask->setEnabled(false);
}
